I have downloaded the dataset from https://www.cbioportal.org/study/summary?id=brca_tcga_pan_can_atlas_2018, unzipped it manually (there was a nested archive inside it, so unzipped that one too). Then I copied the 3 files I need for analysis into the folder Data in my R project folder.

Reading data sets and matching Patient ID with Sample ID

Reading the files. RNA sequences file takes time as it contains around 20,000 lines with ~ 1,000 variables in each line.

# patients clinical data
data_patient = read.delim("Data/data_clinical_patient.txt")

# file with Copy Number Aberrations
data_cna = read.delim("Data/data_cna.txt")

# file with RNA sequences
data_rna_seq = read.delim("Data/data_mrna_seq_v2_rsem.txt")

Top match Patient Data IDs with RNA-seq and CNA identifiers, first looking at the file which provides mapping of a patient clinical info to a sample:

data_mapping = read.delim("Data/data_clinical_sample.txt")
# show the mapping
data_mapping

As can be seen from the mapping, identifiers to uniquely specify a patient follow the format of “TCGA-3C-AAAU” and the corresponding sample identifiers have “-01” at the end, e.g., has a format of “TCGA-3C-AAAU-01”.

The patients clinical data has the following columns:

# inspect column names of the data_patient data frame
colnames(data_patient)
 [1] "X.Patient.Identifier"                                                                       
 [2] "Subtype"                                                                                    
 [3] "TCGA.PanCanAtlas.Cancer.Type.Acronym"                                                       
 [4] "Other.Patient.ID"                                                                           
 [5] "Diagnosis.Age"                                                                              
 [6] "Sex"                                                                                        
 [7] "Neoplasm.Disease.Stage.American.Joint.Committee.on.Cancer.Code"                             
 [8] "American.Joint.Committee.on.Cancer.Publication.Version.Type"                                
 [9] "Last.Communication.Contact.from.Initial.Pathologic.Diagnosis.Date"                          
[10] "Birth.from.Initial.Pathologic.Diagnosis.Date"                                               
[11] "Last.Alive.Less.Initial.Pathologic.Diagnosis.Date.Calculated.Day.Value"                     
[12] "Ethnicity.Category"                                                                         
[13] "Form.completion.date"                                                                       
[14] "Neoadjuvant.Therapy.Type.Administered.Prior.To.Resection.Text"                              
[15] "ICD.10.Classification"                                                                      
[16] "International.Classification.of.Diseases.for.Oncology..Third.Edition.ICD.O.3.Histology.Code"
[17] "International.Classification.of.Diseases.for.Oncology..Third.Edition.ICD.O.3.Site.Code"     
[18] "Informed.consent.verified"                                                                  
[19] "New.Neoplasm.Event.Post.Initial.Therapy.Indicator"                                          
[20] "American.Joint.Committee.on.Cancer.Metastasis.Stage.Code"                                   
[21] "Neoplasm.Disease.Lymph.Node.Stage.American.Joint.Committee.on.Cancer.Code"                  
[22] "American.Joint.Committee.on.Cancer.Tumor.Stage.Code"                                        
[23] "Person.Neoplasm.Cancer.Status"                                                              
[24] "Primary.Lymph.Node.Presentation.Assessment"                                                 
[25] "Prior.Diagnosis"                                                                            
[26] "Race.Category"                                                                              
[27] "Radiation.Therapy"                                                                          
[28] "Patient.Weight"                                                                             
[29] "In.PanCan.Pathway.Analysis"                                                                 
[30] "Overall.Survival.Status"                                                                    
[31] "Overall.Survival..Months."                                                                  
[32] "Disease.specific.Survival.status"                                                           
[33] "Months.of.disease.specific.survival"                                                        
[34] "Disease.Free.Status"                                                                        
[35] "Disease.Free..Months."                                                                      
[36] "Progression.Free.Status"                                                                    
[37] "Progress.Free.Survival..Months."                                                            
[38] "Genetic.Ancestry.Label"                                                                     

The patient ID is the first column named X.Patient.Identifier. Example values of the X.Patient.Identifier column are:

# rows from 6 to 10 of the column with Patient ID
data_patient$X.Patient.Identifier[6:10]
[1] "TCGA-3C-AALI" "TCGA-3C-AALJ" "TCGA-3C-AALK" "TCGA-4H-AAAK" "TCGA-5L-AAT0"

Inspecting column names of the Copy Number Alteration data_cna data frame. The first 10 columns only, since the dataframe has more than 1,000 columns:

str(data_cna, list.len = 10)
'data.frame':   25128 obs. of  1072 variables:
 $ Hugo_Symbol    : chr  "ACAP3" "ACTRT2" "AGRN" "ANKRD65" ...
 $ Entrez_Gene_Id : int  116983 140625 375790 441869 55210 83858 219293 54998 126792 54991 ...
 $ TCGA.3C.AAAU.01: int  0 0 0 0 0 0 0 0 0 0 ...
 $ TCGA.3C.AALI.01: int  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
 $ TCGA.3C.AALJ.01: int  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
 $ TCGA.3C.AALK.01: int  0 0 0 0 0 0 0 0 0 0 ...
 $ TCGA.4H.AAAK.01: int  0 0 0 0 0 0 0 0 0 0 ...
 $ TCGA.5L.AAT0.01: int  0 0 0 0 0 0 0 0 0 0 ...
 $ TCGA.5T.A9QA.01: int  -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
 $ TCGA.A1.A0SB.01: int  0 0 0 0 0 0 0 0 0 0 ...
  [list output truncated]

The output of the str() function showed that in the Copy Number Alterations (CNA) dataset, the first two columns are genes, and the rest columns are Sample IDs. Each Sample ID in CNA dataset can be calculated from the Patient ID by replacing “-” with “.” and adding “01”.

Inspecting the RNA-seq dataframe - the first 10 columns since there are more than 1,000 (one per patient):

str(data_rna_seq, list.len = 10)
'data.frame':   20531 obs. of  1084 variables:
 $ Hugo_Symbol    : chr  "" "" "UBE2Q2P2" "HMGB1P1" ...
 $ Entrez_Gene_Id : int  100130426 100133144 100134869 10357 10431 136542 155060 26823 280660 317712 ...
 $ TCGA.3C.AAAU.01: num  0 16.4 12.9 52.2 408.1 ...
 $ TCGA.3C.AALI.01: num  0 9.27 17.38 69.76 563.89 ...
 $ TCGA.3C.AALJ.01: num  0.907 11.623 9.229 154.297 1360.83 ...
 $ TCGA.3C.AALK.01: num  0 12.1 11.1 143.9 865.5 ...
 $ TCGA.4H.AAAK.01: num  0 6.85 14.43 84.21 766.38 ...
 $ TCGA.5L.AAT0.01: num  0 3.99 13.61 114.26 807.74 ...
 $ TCGA.5T.A9QA.01: num  0 1.46 9 107.56 1420.5 ...
 $ TCGA.A1.A0SB.01: num  0 15.3 14.4 116.4 657.3 ...
  [list output truncated]

The output of the str() function showed that in the RNA-seq dataset, the first two columns are also genes, and remaining columns are Sample IDs.

Same as was observed with the CNA dataset, Sample ID in RNA-seq file can be calculated from the Patient ID by replacing “-” with “.” and adding “01”.

Creation of metadata using the CNA level of ERBB2+ (greater than 0 means amplified)

Metadata is a matrix of the following size: number of rows = number of samples in RNA assay, number of columns = 1.

Element value will be either 1 (ERBB2 Amplified) or 0 (Not Amplified).

# substract all columns with Samples from RNA-seq dataset
# they are all columns except the first two
# and convert into matrix
rna_assay = as.matrix(data_rna_seq[,-c(1,2)])

# give name for rows
rownames(rna_assay) = data_rna_seq[,1]

# check size of rna_assay
print("Size of rna_assay:")
[1] "Size of rna_assay:"
dim(rna_assay)
[1] 20531  1082
# metadata is a matrix of the following size:
# number of rows = number of samples in rna_assay
# number of columns = 1
# initialise with 0
metadataERBB2 = matrix(0, dim(rna_assay)[2], 1)

# size of the metadata matrix
print("Size of metadata matrix:")
[1] "Size of metadata matrix:"
dim(metadataERBB2)
[1] 1082    1

Logic to fill in the metadata matrix:

# iterate over each sample in the RNA assay and 
# take a sample ID
# and use it to retrieve an element in the CNA dataset at the position:
#     row = row in which the Hugo_Symbol is equal to ERBB2 gene
#     column = column which has the name equal to the current sample ID
for (i in 1:dim(rna_assay)[2]){
  
  # each column name in RNA assay is a Sample ID
  sample_id = colnames(rna_assay)[i]

  value = data_cna[data_cna$Hugo_Symbol == "ERBB2", sample_id]
  
  if (length(value) > 0 && !is.na(value)){
    
    if (value > 0) amplified = 1
    else amplified = 0 
    
    # write the value into the metadata matrix
    metadataERBB2[i,1] = amplified
  }
}

# give the single column of the metadata matrix a name
colnames(metadataERBB2)[1] = "Amplified"

# give names to rows of the metadata matrix, which are Sample IDs
# they should be equal to column names of the RNA assay (Sample IDs)
rownames(metadataERBB2) = colnames(rna_assay)

View the metadata matrix:

print(head(metadataERBB2,10))
                Amplified
TCGA.3C.AAAU.01         0
TCGA.3C.AALI.01         1
TCGA.3C.AALJ.01         1
TCGA.3C.AALK.01         1
TCGA.4H.AAAK.01         1
TCGA.5L.AAT0.01         0
TCGA.5T.A9QA.01         1
TCGA.A1.A0SB.01         0
TCGA.A1.A0SD.01         0
TCGA.A1.A0SE.01         0

It can be seen that the matrix has row names equal to Sample IDs, and a single column “Amplified” containing 0 or 1.

Checking that there are no NA in the metadata. There shouldn’t be any NA because the matrix was initialised with 0.

print(all(!is.na(metadataERBB2)))
[1] TRUE

Installing packages for Differential Expression Genes (DEG) analysis:

if (!require("BiocManager", quietly = TRUE))
  suppressMessages(suppressWarnings(install.packages("BiocManager")))

# Install DeSeq2
suppressMessages(suppressWarnings(BiocManager::install("DESeq2")))

suppressMessages(library(DESeq2))

For DEG analysis, need to construct an object of the type DESeqDataSet which contains input values, intermediate calculations and results of DEG analysis. I will use the DESeqDataSetFromMatrix function from the DESeq2 package.

Data preparation:

# round the values in rna_assay,
# because DESeq expects input as counts as are integer numbers
rna_assay = round(rna_assay)

rna_assay[is.na(rna_assay)] = 0  # replace NA with zeros
rna_assay[rna_assay < 0] = 0 # replace negative values with zeros

# filter out genes with too many missing values 
# keep the gene (row) only if it has at least 3 samples with value > 10
smallestGroupSize = 3

# vector that contains TRUE or FALSE for each gene
keep_gene = rowSums(rna_assay >= 10) >= smallestGroupSize 

# keep rows only if keep_gene = TRUE for that row
rna_assay = rna_assay[keep_gene,] 

Checking the size after rows with many missing values were removed:

print(
  paste("Size of the RNA assay after removing genes with low counts: ",
        paste(dim(rna_assay), collapse = " x ")))
[1] "Size of the RNA assay after removing genes with low counts:  18603 x 1082"

It can be seen that around 2,000 genes were removed and 18,603 genes were kept.

Creating the DESeqDataSet object, which contains inputs, intermediate calculation, and result of DEG analysis:

# create DESeqDataSet instance
dds =  DESeqDataSetFromMatrix(
  countData = rna_assay, # input with counts for genes
  colData = metadataERBB2, # colData rows must match countData columns
  design = ~ Amplified) # formula how the counts for each gene depend on colData
converting counts to integer mode
Warning in DESeqDataSet(se, design = design, ignoreRank) :
  13 duplicate rownames were renamed by adding numbers
  the design formula contains one or more numeric variables with integer values,
  specifying a model with increasing fold change for higher values.
  did you mean for this to be a factor? if so, first convert
  this variable to a factor using the factor() function

The counts that I provided in the rna_assay are not normalized, and this is expected by the DESeq() function, based on the documentation at bioconducter.org.

Run differential expression analysis

The DESEq() function performs estimation of size factors, estimation of dispersion, Negative Binomial GLM fitting and Wald statistics.

# Run differential expression analysis
dds <- DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 3023 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing

Names of the estimated effects (coefficients) of the model:

resultsNames(dds)
[1] "Intercept" "Amplified"

To access results of DEG analysis, calling the results() function:

res = results(dds)

Top 10 most differentially expressed genes ordered by p-adjusted value:

# order by p-adjusted value
top_10_genes_padj = res[order(res$padj)[1:10],]
# print
print(top_10_genes_padj)
log2 fold change (MLE): Amplified 
Wald test p-value: Amplified 
DataFrame with 10 rows and 6 columns
          baseMean log2FoldChange     lfcSE      stat       pvalue         padj
         <numeric>      <numeric> <numeric> <numeric>    <numeric>    <numeric>
PSMD3      5059.91        2.04226 0.0579065   35.2683 1.79889e-272 3.34647e-268
STARD3     1694.82        2.18348 0.0625963   34.8819 1.39645e-266 1.29891e-262
ERBB2     18345.66        2.77945 0.0797532   34.8506 4.16245e-266 2.58113e-262
C17orf37   1959.93        2.42679 0.0703565   34.4928 1.02688e-260 4.77575e-257
GRB7       1308.10        2.59843 0.0789146   32.9271 9.00268e-238 3.34954e-234
PGAP3      1917.73        2.28601 0.0708165   32.2807 1.30456e-228 4.04479e-225
ORMDL3     3966.57        2.06060 0.0658508   31.2919 6.00605e-215 1.59615e-211
MED1       2541.95        1.81671 0.0601066   30.2248 1.11900e-200 2.60210e-197
MSL1       3083.81        1.39581 0.0494692   28.2158 3.74688e-175 7.74480e-172
CDK12      2051.81        1.47018 0.0523967   28.0587 3.12751e-173 5.81811e-170

Top 10 upregulated genes based on the fold change:

# order by log2 fold change
# when using descending order, log2 > 0
# and so returns top 10 upregulated genes
top_10_genes_log2fc_up = res[order(res$log2FoldChange, decreasing = TRUE)[1:10],]
print(top_10_genes_log2fc_up)
log2 fold change (MLE): Amplified 
Wald test p-value: Amplified 
DataFrame with 10 rows and 6 columns
         baseMean log2FoldChange     lfcSE      stat      pvalue        padj
        <numeric>      <numeric> <numeric> <numeric>   <numeric>   <numeric>
SPANXA2   2.31235        4.35987  0.633290   6.88447 5.80022e-12 1.01221e-10
GAGE12D  10.12361        4.32213  0.792895   5.45108 5.00657e-08 4.09215e-07
SPANXC    2.41072        4.13850  0.521456   7.93644 2.08071e-15 6.83879e-14
GAGE2B    1.50314        4.06720  1.417492   2.86929 4.11391e-03 9.95721e-03
FAM9C     1.67308        3.39339  0.297496  11.40651 3.87983e-30 5.50965e-28
GAGE4     4.39471        3.33288  0.672714   4.95438 7.25601e-07 4.55881e-06
PNMT    163.64015        3.29807  0.178970  18.42806 7.82327e-76 5.59755e-73
KRT20     3.49946        3.06552  0.434159   7.06083 1.65515e-12 3.23433e-11
TBX10     8.58797        3.00122  0.398242   7.53619 4.83907e-14 1.26434e-12
GAGE2D    4.03952        2.95668  0.751347   3.93518 8.31351e-05 3.15812e-04

Top 10 downregulated genes based on the fold change:

# order by log2 fold change
# when using ascending order, log2 < 0
# and so returns top 10 downregulated genes
top_10_genes_log2fc_down = res[order(res$log2FoldChange, decreasing = FALSE)[1:10],]
print(top_10_genes_log2fc_down)
log2 fold change (MLE): Amplified 
Wald test p-value: Amplified 
DataFrame with 10 rows and 6 columns
        baseMean log2FoldChange     lfcSE      stat      pvalue        padj
       <numeric>      <numeric> <numeric> <numeric>   <numeric>   <numeric>
CSN2    18.33147       -4.54022  0.827808  -5.48463 4.14340e-08 3.44567e-07
SMR3B   60.73650       -3.76811  0.421180  -8.94655 3.66770e-19 1.91121e-17
CSN3    47.97724       -3.72842  0.489189  -7.62164 2.50471e-14 6.87244e-13
LALBA   26.22764       -3.49553  0.721085  -4.84761 1.24960e-06 7.41982e-06
LACRT   30.24219       -3.23241  0.506075  -6.38722 1.68932e-10 2.29390e-09
NTS     43.91369       -3.16044  0.307213 -10.28746 8.02694e-25 7.77735e-23
CARTPT 302.97827       -3.02651  0.557301  -5.43067 5.61435e-08 4.52922e-07
RLBP1    3.39960       -3.01570  0.409080  -7.37191 1.68201e-13 3.99113e-12
UCP1     6.78740       -3.00797  0.313735  -9.58759 9.01657e-22 6.40211e-20
CSN1S1   4.61509       -2.85141  0.456347  -6.24834 4.14836e-10 5.15167e-09

Pathway Enrichment

Required packages:

if (!requireNamespace("clusterProfiler", quietly = TRUE))
  BiocManager::install("clusterProfiler", quit = TRUE)
if (!requireNamespace("org.Hs.eg.db", quietly = TRUE))
  BiocManager::install("org.Hs.eg.db")
if (!requireNamespace("enrichplot", quietly = TRUE))
  install.packages("enrichplot")

library(clusterProfiler)
library(enrichplot)
library(org.Hs.eg.db)

Using differential expressed genes, which were obtained by DESeq() function, with p-adjusted < 0.05:

# filter DESEq results to keep 
# differentially expressed genes with p-adjusted < 0.05
res_significant = res[res$padj<0.05,]

# separate into over- and underexpressed by log2 fold change

# overexpressed
res_over  = rownames(res_significant[res_significant$log2FoldChange > 0,])

# underexpressed
res_under = rownames(res_significant[res_significant$log2FoldChange < 0,])

Gene Ontology (GO) enrichment analysis:

# GO enrichment analysis
go_results_over = enrichGO(
  gene          = res_over, # overexpressed genes list
  OrgDb         = org.Hs.eg.db, # humans
  keyType       = "SYMBOL",  
  ont           = "BP", # biological processes
  pAdjustMethod = "BH", 
  pvalueCutoff  = 0.05,
  qvalueCutoff  = 0.05
)

Enriched biological processes associated with the overexpressed genes:

# print top 6 results
print(head(go_results_over[,1-10]))

Plot of enriched biological processes:

dotplot(go_results_over, showCategory = 10) + 
  ggtitle("Gene Ontology Enrichment - overexpressed")

GO analysis of the underexpressed genes:

go_results_under = enrichGO(
  gene          = res_under, # under expressed genes list
  OrgDb         = org.Hs.eg.db, # humans
  keyType       = "SYMBOL",  
  ont           = "BP", # biological processes
  pAdjustMethod = "BH", 
  pvalueCutoff  = 0.05,
  qvalueCutoff  = 0.05
)

Enriched biological processes associated with the underexpressed genes:

# print top 6 results
print(head(go_results_under))

Plot of the enriched pathways related to the underexpressed genes:

dotplot(go_results_under, showCategory = 10) +
  ggtitle("Gene Ontology Enrichment - Underexpressed")

Installing packages for pathway enrichment analysis using Reactome:

if (!requireNamespace("pathview", quietly = TRUE))
  BiocManager::install("pathview")
if (!requireNamespace("ReactomePA", quietly = TRUE))
  BiocManager::install("ReactomePA")

library(ReactomePA)
library(pathview)

KEGG (Kyoto Encyclopedia of Genes and Genomes) enrichment analysis:

# map genes codes to entrez - required to use Reactome and Kegg functions
gene_entrez_over = bitr(
  res_over,
  fromType = "SYMBOL",
  toType   = "ENTREZID",
  OrgDb    = org.Hs.eg.db
)

gene_entrez_under = bitr(
  res_under,
  fromType = "SYMBOL",
  toType   = "ENTREZID",
  OrgDb    = org.Hs.eg.db
)

kegg_results_over = enrichKEGG(
  gene          = gene_entrez_over[,2],
  organism      = "human",   
  pAdjustMethod = "BH",
  pvalueCutoff  = 0.05,
  qvalueCutoff  = 0.05
)

kegg_results_under = enrichKEGG(
  gene          = gene_entrez_under[,2],
  organism      = "human",   
  pAdjustMethod = "BH",
  pvalueCutoff  = 0.05,
  qvalueCutoff  = 0.05
)

Significantly enriched KEGG pathways or functional categories for most overexpressed genes:

print(head(kegg_results_over))
dotplot(kegg_results_over, showCategory = 10) + ggtitle("Kegg - overexpressed")

Significantly enriched KEGG pathways or functional categories for most underxpressed genes:

print(head(kegg_results_under))
dotplot(kegg_results_under, showCategory = 10) + ggtitle("Kegg - underexpressed")

Reactome results.

reactome_results_over = enrichPathway(
  gene          = gene_entrez_over[,2],
  organism      = "human",   
  pAdjustMethod = "BH",
  pvalueCutoff  = 0.05,
  qvalueCutoff  = 0.05,
)

reactome_results_under = enrichPathway(
  gene          = gene_entrez_under[,2],
  organism      = "human",   
  pAdjustMethod = "BH",
  pvalueCutoff  = 0.05,
  qvalueCutoff  = 0.05,
)

Pathways associated with overexpressed genes:

print(head(reactome_results_over))
dotplot(reactome_results_over, showCategory = 10) + ggtitle("Reactome - overxpressed")

Pathways associated with underexpressed genes:

print(head(reactome_results_under))
dotplot(reactome_results_under, showCategory=10) + ggtitle("Reactome - underexpressed")

Variance stabilised transformed expression values

Applying a variance stabilizing transformation (VST) to the RNA-seq count data. VST automatically normalizes the count data, providing matrix of values which are approximately homoskedastic (have constant variance along the range of mean values).

# variance stabilizing transformation
vst = vst(dds)

PCA plot and a heatmap

PCA plot:

# PCA plot of the vst results grouped by the Amplified status
plotPCA(vst, intgroup=c("Amplified"))
using ntop=500 top features by variance

Pacakges for Heatmap:

# install packages for heatmap 
if (!requireNamespace("pheatmap", quietly = TRUE))
  install.packages("pheatmap")

library(pheatmap)

Subset of the most differentially expressed genes to visualize:

# sort by p-adjusted 
genes_sorted = order(res$padj)

# VST results for top 20 genes
vst_top20 = assay(vst)[genes_sorted[1:20],]

Plotting the heatmap:

# column for annotation
annotation_column = as.data.frame(colData(dds)[, "Amplified", drop = FALSE])

# colors for annotation
# annotation_colors = list(c("High" = "darkred", "Low" = "lightblue"))

pheatmap(
  vst_top20,
  cluster_rows = TRUE,      
  cluster_cols = TRUE,  
  scale = 'row',
  show_colnames = FALSE,
  show_rownames = TRUE,
  annotation_col = annotation_column,
  main = "Heatmap of Gene Expression by ERBB2 Amplified status")

Overall survival model using the glmnet package

Packages:

library(survminer)
Loading required package: ggplot2
Loading required package: ggpubr

Attaching package: ‘ggpubr’

The following object is masked from ‘package:enrichplot’:

    color_palette


Attaching package: ‘survminer’

The following object is masked from ‘package:survival’:

    myeloma

Data preparation: extracting survival times (non-zero and non NA), event status and the corresponding subset of the VST matrix. VST matrix is subset based on correspondence of Sample ID and Patient ID from a clinical info data:

# vst-transformed matrix
vst_matrix = assay(vst)
# transform patient identifier to match sample IDs in vst_matrix
# as a result, transforms TCGA-3C-AAAU to TCGA.3C.AAAU
sample_ids = gsub("-", ".", data_patient$X.Patient.Identifier[5:nrow(data_patient)])
# extract sample ids from vst without suffix .01
sample_ids_vst = substr(colnames(vst_matrix), 1, 12)

# convert survival_time and event_status to numeric 
survival_time = as.numeric(data_patient$Overall.Survival..Months.[5:nrow(data_patient)])
event_status = data_patient$Overall.Survival.Status[5:nrow(data_patient)] 
event_status = ifelse(event_status == "1:DECEASED", 1, 0)

# filter out survival time that are less than equal 0
valid_index = which(survival_time > 0) 
survival_time = survival_time[valid_index] 
event_status = event_status[valid_index] 
sample_ids = sample_ids[valid_index]

# remove rows with NA values
complete_cases_index = complete.cases(survival_time, event_status) 
survival_time = survival_time[complete_cases_index] 
event_status = event_status[complete_cases_index] 
sample_ids = sample_ids[complete_cases_index]
# match sample IDs derived from Patient IDs and VST sample IDs
# keep those that present in both
matching_ids = intersect(sample_ids, sample_ids_vst)
# their indexes
matching_index = which(sample_ids %in% matching_ids)
# subset survival_time and event_status by indexes of matching ids
survival_time = survival_time[matching_index]
event_status = event_status[matching_index]
# subset vst_matrix by matching ids 
matching_ids_vst = colnames(vst_matrix)[substr(colnames(vst_matrix), 1, 12) %in% matching_ids]

vst_matrix = vst_matrix[, matching_ids_vst]

Transpose vst_matrix so that samples are rows, genes are columns:

vst_matrix = t(vst_matrix)

Check no NA:

sum(is.na(survival_time))  
[1] 0
sum(is.na(event_status)) 
[1] 0
sum(is.na(vst_matrix)) 
[1] 0

Create survival object:

survival_object = Surv(time = survival_time, event = event_status) 

Cox model with alpha = 1 to apply lasso penalty:

# Cox model and Lasso regularization using glmnet 
cox_model = glmnet(vst_matrix, 
                   survival_object, 
                   family = "cox",
                   alpha = 1) # lasso penalty

K-fold (5) cross-validation for glmnet:

# produces a plot and returns a value for lambda
cv_fit = cv.glmnet(vst_matrix,
                   survival_object,
                   family = "cox",
                   nfolds = 5) # reduced to 5 due to slow execution

# best lambda
best_lambda = cv_fit$lambda.min
print(best_lambda)
[1] 0.03949631

Survival risk:

# survival risk
risk_score = predict(cox_model,
                     s = best_lambda,
                     newx = vst_matrix)

print(head(risk_score))
                       1
TCGA.3C.AAAU.01 1.972002
TCGA.3C.AALI.01 2.145560
TCGA.3C.AALJ.01 2.189554
TCGA.3C.AALK.01 2.010798
TCGA.4H.AAAK.01 2.027707
TCGA.5L.AAT0.01 1.930621

Plot data:

LS0tCnRpdGxlOiAiQnJlYXN0IENhbmNlcjogR2VuZSBFeHByZXNzaW9uIEFuYWx5c2lzIGFuZCBJbnRlcnByZXRhdGlvbiIKYXV0aG9yOiAiRWxlbmEgRXZkb2tpbWVua28iIApkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiwgJVknKWAiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkkgaGF2ZSBkb3dubG9hZGVkIHRoZSBkYXRhc2V0IGZyb20gPGh0dHBzOi8vd3d3LmNiaW9wb3J0YWwub3JnL3N0dWR5L3N1bW1hcnk/aWQ9YnJjYV90Y2dhX3Bhbl9jYW5fYXRsYXNfMjAxOD4sIHVuemlwcGVkIGl0IG1hbnVhbGx5ICh0aGVyZSB3YXMgYSBuZXN0ZWQgYXJjaGl2ZSBpbnNpZGUgaXQsIHNvIHVuemlwcGVkIHRoYXQgb25lIHRvbykuIFRoZW4gSSBjb3BpZWQgdGhlIDMgZmlsZXMgSSBuZWVkIGZvciBhbmFseXNpcyBpbnRvIHRoZSBmb2xkZXIgKkRhdGEqIGluIG15IFIgcHJvamVjdCBmb2xkZXIuCgojIyBSZWFkaW5nIGRhdGEgc2V0cyBhbmQgbWF0Y2hpbmcgUGF0aWVudCBJRCB3aXRoIFNhbXBsZSBJRCAKClJlYWRpbmcgdGhlIGZpbGVzLiBSTkEgc2VxdWVuY2VzIGZpbGUgdGFrZXMgdGltZSBhcyBpdCBjb250YWlucyBhcm91bmQgMjAsMDAwIGxpbmVzIHdpdGggfiAxLDAwMCB2YXJpYWJsZXMgaW4gZWFjaCBsaW5lLgoKYGBge3J9CiMgcGF0aWVudHMgY2xpbmljYWwgZGF0YQpkYXRhX3BhdGllbnQgPSByZWFkLmRlbGltKCJEYXRhL2RhdGFfY2xpbmljYWxfcGF0aWVudC50eHQiKQoKIyBmaWxlIHdpdGggQ29weSBOdW1iZXIgQWx0ZXJhdGlvbnMKZGF0YV9jbmEgPSByZWFkLmRlbGltKCJEYXRhL2RhdGFfY25hLnR4dCIpCgojIGZpbGUgd2l0aCBSTkEgc2VxdWVuY2VzCmRhdGFfcm5hX3NlcSA9IHJlYWQuZGVsaW0oIkRhdGEvZGF0YV9tcm5hX3NlcV92Ml9yc2VtLnR4dCIpCmBgYAoKVG9wIG1hdGNoIFBhdGllbnQgRGF0YSBJRHMgd2l0aCBSTkEtc2VxIGFuZCBDTkEgaWRlbnRpZmllcnMsIGZpcnN0IGxvb2tpbmcgYXQgdGhlIGZpbGUgd2hpY2ggcHJvdmlkZXMgbWFwcGluZyBvZiBhIHBhdGllbnQgY2xpbmljYWwgaW5mbyB0byBhIHNhbXBsZToKCmBgYHtyfQpkYXRhX21hcHBpbmcgPSByZWFkLmRlbGltKCJEYXRhL2RhdGFfY2xpbmljYWxfc2FtcGxlLnR4dCIpCiMgc2hvdyB0aGUgbWFwcGluZwpkYXRhX21hcHBpbmcKYGBgCkFzIGNhbiBiZSBzZWVuIGZyb20gdGhlIG1hcHBpbmcsIGlkZW50aWZpZXJzIHRvIHVuaXF1ZWx5IHNwZWNpZnkgYSBwYXRpZW50IGZvbGxvdyB0aGUgZm9ybWF0IG9mICJUQ0dBLTNDLUFBQVUiIGFuZCB0aGUgY29ycmVzcG9uZGluZyBzYW1wbGUgaWRlbnRpZmllcnMgaGF2ZSAiLTAxIiBhdCB0aGUgZW5kLCBlLmcuLCBoYXMgYSBmb3JtYXQgb2YgIlRDR0EtM0MtQUFBVS0wMSIuCgpUaGUgcGF0aWVudHMgY2xpbmljYWwgZGF0YSBoYXMgdGhlIGZvbGxvd2luZyBjb2x1bW5zOgoKYGBge3J9CiMgaW5zcGVjdCBjb2x1bW4gbmFtZXMgb2YgdGhlIGRhdGFfcGF0aWVudCBkYXRhIGZyYW1lCmNvbG5hbWVzKGRhdGFfcGF0aWVudCkKYGBgCgpUaGUgcGF0aWVudCBJRCBpcyB0aGUgZmlyc3QgY29sdW1uIG5hbWVkIGBYLlBhdGllbnQuSWRlbnRpZmllcmAuIEV4YW1wbGUgdmFsdWVzIG9mIHRoZSBgWC5QYXRpZW50LklkZW50aWZpZXJgIGNvbHVtbiBhcmU6CQpgYGB7cn0KIyByb3dzIGZyb20gNiB0byAxMCBvZiB0aGUgUGF0aWVudCBJRCBjb2x1bW4KZGF0YV9wYXRpZW50JFguUGF0aWVudC5JZGVudGlmaWVyWzY6MTBdCmBgYAoKSW5zcGVjdGluZyBjb2x1bW4gbmFtZXMgb2YgdGhlIENvcHkgTnVtYmVyIEFsdGVyYXRpb24gZGF0YV9jbmEgZGF0YSBmcmFtZS4gVGhlIGZpcnN0IDEwIGNvbHVtbnMgb25seSwgc2luY2UgdGhlIGRhdGFmcmFtZSBoYXMgbW9yZSB0aGFuIDEsMDAwIGNvbHVtbnM6CgpgYGB7cn0Kc3RyKGRhdGFfY25hLCBsaXN0LmxlbiA9IDEwKQpgYGAKVGhlIG91dHB1dCBvZiB0aGUgYHN0cigpYCBmdW5jdGlvbiBzaG93ZWQgdGhhdCBpbiB0aGUgQ29weSBOdW1iZXIgQWx0ZXJhdGlvbnMgKENOQSkgZGF0YXNldCwgdGhlIGZpcnN0IHR3byBjb2x1bW5zIGFyZSBnZW5lcywgYW5kIHRoZSByZXN0IGNvbHVtbnMgYXJlIFNhbXBsZSBJRHMuIEVhY2ggKipTYW1wbGUgSUQgaW4gQ05BIGRhdGFzZXQgY2FuIGJlIGNhbGN1bGF0ZWQgZnJvbSB0aGUgUGF0aWVudCBJRCoqIGJ5IHJlcGxhY2luZyAiLSIgd2l0aCAiLiIgYW5kIGFkZGluZyAiMDEiLgoKSW5zcGVjdGluZyB0aGUgUk5BLXNlcSBkYXRhZnJhbWUgLSB0aGUgZmlyc3QgMTAgY29sdW1ucyBzaW5jZSB0aGVyZSBhcmUgbW9yZSB0aGFuIDEsMDAwIChvbmUgcGVyIHBhdGllbnQpOgoKYGBge3J9CnN0cihkYXRhX3JuYV9zZXEsIGxpc3QubGVuID0gMTApCmBgYApUaGUgb3V0cHV0IG9mIHRoZSBgc3RyKClgIGZ1bmN0aW9uIHNob3dlZCB0aGF0IGluIHRoZSBSTkEtc2VxIGRhdGFzZXQsIHRoZSBmaXJzdCB0d28gY29sdW1ucyBhcmUgYWxzbyBnZW5lcywgYW5kIHJlbWFpbmluZyBjb2x1bW5zIGFyZSBTYW1wbGUgSURzLiAgCgpTYW1lIGFzIHdhcyBvYnNlcnZlZCB3aXRoIHRoZSBDTkEgZGF0YXNldCwgKipTYW1wbGUgSUQgaW4gUk5BLXNlcSBmaWxlIGNhbiBiZSBjYWxjdWxhdGVkIGZyb20gdGhlIFBhdGllbnQgSUQqKiBieSByZXBsYWNpbmcgIi0iIHdpdGggIi4iIGFuZCBhZGRpbmcgIjAxIi4KCiMjIENyZWF0aW9uIG9mIG1ldGFkYXRhIHVzaW5nIHRoZSBDTkEgbGV2ZWwgb2YgRVJCQjIrIChncmVhdGVyIHRoYW4gMCBtZWFucyBhbXBsaWZpZWQpCgpNZXRhZGF0YSBpcyBhIG1hdHJpeCBvZiB0aGUgZm9sbG93aW5nIHNpemU6CiBudW1iZXIgb2Ygcm93cyA9IG51bWJlciBvZiBzYW1wbGVzIGluIFJOQSBhc3NheSwKIG51bWJlciBvZiBjb2x1bW5zID0gMS4KCkVsZW1lbnQgdmFsdWUgd2lsbCBiZSBlaXRoZXIgMSAoRVJCQjIgQW1wbGlmaWVkKSBvciAwIChOb3QgQW1wbGlmaWVkKS4KCmBgYHtyfQojIHN1YnN0cmFjdCBhbGwgY29sdW1ucyB3aXRoIFNhbXBsZXMgZnJvbSBSTkEtc2VxIGRhdGFzZXQKIyB0aGV5IGFyZSBhbGwgY29sdW1ucyBleGNlcHQgdGhlIGZpcnN0IHR3bwojIGFuZCBjb252ZXJ0IGludG8gbWF0cml4CnJuYV9hc3NheSA9IGFzLm1hdHJpeChkYXRhX3JuYV9zZXFbLC1jKDEsMildKQoKIyBnaXZlIG5hbWUgZm9yIHJvd3MKcm93bmFtZXMocm5hX2Fzc2F5KSA9IGRhdGFfcm5hX3NlcVssMV0KCiMgY2hlY2sgc2l6ZSBvZiBybmFfYXNzYXkKcHJpbnQoIlNpemUgb2Ygcm5hX2Fzc2F5OiIpCmRpbShybmFfYXNzYXkpCgojIG1ldGFkYXRhIGlzIGEgbWF0cml4IG9mIHRoZSBmb2xsb3dpbmcgc2l6ZToKIyBudW1iZXIgb2Ygcm93cyA9IG51bWJlciBvZiBzYW1wbGVzIGluIHJuYV9hc3NheQojIG51bWJlciBvZiBjb2x1bW5zID0gMQojIGluaXRpYWxpc2Ugd2l0aCAwCm1ldGFkYXRhRVJCQjIgPSBtYXRyaXgoMCwgZGltKHJuYV9hc3NheSlbMl0sIDEpCgojIHNpemUgb2YgdGhlIG1ldGFkYXRhIG1hdHJpeApwcmludCgiU2l6ZSBvZiBtZXRhZGF0YSBtYXRyaXg6IikKZGltKG1ldGFkYXRhRVJCQjIpCmBgYApMb2dpYyB0byBmaWxsIGluIHRoZSBtZXRhZGF0YSBtYXRyaXg6IAoKYGBge3J9CiMgaXRlcmF0ZSBvdmVyIGVhY2ggc2FtcGxlIGluIHRoZSBSTkEgYXNzYXkgYW5kIAojIHRha2UgYSBzYW1wbGUgSUQKIyBhbmQgdXNlIGl0IHRvIHJldHJpZXZlIGFuIGVsZW1lbnQgaW4gdGhlIENOQSBkYXRhc2V0IGF0IHRoZSBwb3NpdGlvbjoKIyAgICAgcm93ID0gcm93IGluIHdoaWNoIHRoZSBIdWdvX1N5bWJvbCBpcyBlcXVhbCB0byBFUkJCMiBnZW5lCiMgICAgIGNvbHVtbiA9IGNvbHVtbiB3aGljaCBoYXMgdGhlIG5hbWUgZXF1YWwgdG8gdGhlIGN1cnJlbnQgc2FtcGxlIElECmZvciAoaSBpbiAxOmRpbShybmFfYXNzYXkpWzJdKXsKICAKICAjIGVhY2ggY29sdW1uIG5hbWUgaW4gUk5BIGFzc2F5IGlzIGEgU2FtcGxlIElECiAgc2FtcGxlX2lkID0gY29sbmFtZXMocm5hX2Fzc2F5KVtpXQoKICB2YWx1ZSA9IGRhdGFfY25hW2RhdGFfY25hJEh1Z29fU3ltYm9sID09ICJFUkJCMiIsIHNhbXBsZV9pZF0KICAKICBpZiAobGVuZ3RoKHZhbHVlKSA+IDAgJiYgIWlzLm5hKHZhbHVlKSl7CiAgICAKICAgIGlmICh2YWx1ZSA+IDApIGFtcGxpZmllZCA9IDEKICAgIGVsc2UgYW1wbGlmaWVkID0gMCAKICAgIAogICAgIyB3cml0ZSB0aGUgdmFsdWUgaW50byB0aGUgbWV0YWRhdGEgbWF0cml4CiAgICBtZXRhZGF0YUVSQkIyW2ksMV0gPSBhbXBsaWZpZWQKICB9Cn0KCiMgZ2l2ZSB0aGUgc2luZ2xlIGNvbHVtbiBvZiB0aGUgbWV0YWRhdGEgbWF0cml4IGEgbmFtZQpjb2xuYW1lcyhtZXRhZGF0YUVSQkIyKVsxXSA9ICJBbXBsaWZpZWQiCgojIGdpdmUgbmFtZXMgdG8gcm93cyBvZiB0aGUgbWV0YWRhdGEgbWF0cml4LCB3aGljaCBhcmUgU2FtcGxlIElEcwojIHRoZXkgc2hvdWxkIGJlIGVxdWFsIHRvIGNvbHVtbiBuYW1lcyBvZiB0aGUgUk5BIGFzc2F5IChTYW1wbGUgSURzKQpyb3duYW1lcyhtZXRhZGF0YUVSQkIyKSA9IGNvbG5hbWVzKHJuYV9hc3NheSkKYGBgCgpWaWV3IHRoZSBtZXRhZGF0YSBtYXRyaXg6CgpgYGB7cn0KIyBmaXJzdCAxMCByb3dzCnByaW50KGhlYWQobWV0YWRhdGFFUkJCMiwxMCkpCmBgYAoKSXQgY2FuIGJlIHNlZW4gdGhhdCB0aGUgbWF0cml4IGhhcyByb3cgbmFtZXMgZXF1YWwgdG8gU2FtcGxlIElEcywgYW5kIGEgc2luZ2xlIGNvbHVtbiAiQW1wbGlmaWVkIiBjb250YWluaW5nIDAgb3IgMS4KCkNoZWNraW5nIHRoYXQgdGhlcmUgYXJlIG5vIE5BIGluIHRoZSBtZXRhZGF0YS4gVGhlcmUgc2hvdWxkbid0IGJlIGFueSBOQSBiZWNhdXNlIHRoZSBtYXRyaXggd2FzIGluaXRpYWxpc2VkIHdpdGggMC4KCmBgYHtyfQojIHByaW50IFRSVUUgaWYgdGhlcmUgYXJlIG5vIE5BIGluIHRoZSBtYXRyaXgKcHJpbnQoYWxsKCFpcy5uYShtZXRhZGF0YUVSQkIyKSkpCmBgYApJbnN0YWxsaW5nIHBhY2thZ2VzIGZvciBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBHZW5lcyAoREVHKSBhbmFseXNpczoKCmBgYHtyfQppZiAoIXJlcXVpcmUoIkJpb2NNYW5hZ2VyIiwgcXVpZXRseSA9IFRSVUUpKQogIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikKCiMgSW5zdGFsbCBEZVNlcTIKQmlvY01hbmFnZXI6Omluc3RhbGwoIkRFU2VxMiIpCgpsaWJyYXJ5KERFU2VxMikKYGBgCgpGb3IgREVHIGFuYWx5c2lzLCBuZWVkIHRvIGNvbnN0cnVjdCBhbiBvYmplY3Qgb2YgdGhlIHR5cGUgYERFU2VxRGF0YVNldGAgd2hpY2ggY29udGFpbnMgaW5wdXQgdmFsdWVzLCBpbnRlcm1lZGlhdGUgY2FsY3VsYXRpb25zIGFuZCByZXN1bHRzIG9mIERFRyBhbmFseXNpcy4gSSB3aWxsIHVzZSB0aGUgYERFU2VxRGF0YVNldEZyb21NYXRyaXhgIGZ1bmN0aW9uIGZyb20gdGhlIGBERVNlcTJgIHBhY2thZ2UuCgpEYXRhIHByZXBhcmF0aW9uOgoKYGBge3J9CiMgcm91bmQgdGhlIHZhbHVlcyBpbiBybmFfYXNzYXksCiMgYmVjYXVzZSBERVNlcSBleHBlY3RzIGlucHV0IGFzIGNvdW50cyBhcyBhcmUgaW50ZWdlciBudW1iZXJzCnJuYV9hc3NheSA9IHJvdW5kKHJuYV9hc3NheSkKCnJuYV9hc3NheVtpcy5uYShybmFfYXNzYXkpXSA9IDAgICMgcmVwbGFjZSBOQSB3aXRoIHplcm9zCnJuYV9hc3NheVtybmFfYXNzYXkgPCAwXSA9IDAgIyByZXBsYWNlIG5lZ2F0aXZlIHZhbHVlcyB3aXRoIHplcm9zCgojIGZpbHRlciBvdXQgZ2VuZXMgd2l0aCB0b28gbWFueSBtaXNzaW5nIHZhbHVlcyAKIyBrZWVwIHRoZSBnZW5lIChyb3cpIG9ubHkgaWYgaXQgaGFzIGF0IGxlYXN0IDMgc2FtcGxlcyB3aXRoIHZhbHVlID4gMTAKc21hbGxlc3RHcm91cFNpemUgPSAzCgojIHZlY3RvciB0aGF0IGNvbnRhaW5zIFRSVUUgb3IgRkFMU0UgZm9yIGVhY2ggZ2VuZQprZWVwX2dlbmUgPSByb3dTdW1zKHJuYV9hc3NheSA+PSAxMCkgPj0gc21hbGxlc3RHcm91cFNpemUgCgojIGtlZXAgcm93cyBvbmx5IGlmIGtlZXBfZ2VuZSA9IFRSVUUgZm9yIHRoYXQgcm93CnJuYV9hc3NheSA9IHJuYV9hc3NheVtrZWVwX2dlbmUsXSAKYGBgCgpDaGVja2luZyB0aGUgc2l6ZSBhZnRlciByb3dzIHdpdGggbWFueSBtaXNzaW5nIHZhbHVlcyB3ZXJlIHJlbW92ZWQ6CgpgYGB7cn0KcHJpbnQoCiAgcGFzdGUoIlNpemUgb2YgdGhlIFJOQSBhc3NheSBhZnRlciByZW1vdmluZyBnZW5lcyB3aXRoIGxvdyBjb3VudHM6ICIsCiAgICAgICAgcGFzdGUoZGltKHJuYV9hc3NheSksIGNvbGxhcHNlID0gIiB4ICIpKSkKYGBgCgpJdCBjYW4gYmUgc2VlbiB0aGF0IGFyb3VuZCAyLDAwMCBnZW5lcyB3ZXJlIHJlbW92ZWQgYW5kIDE4LDYwMyBnZW5lcyB3ZXJlIGtlcHQuIAoKQ3JlYXRpbmcgdGhlIGBERVNlcURhdGFTZXRgIG9iamVjdCwgd2hpY2ggY29udGFpbnMgaW5wdXRzLCBpbnRlcm1lZGlhdGUgY2FsY3VsYXRpb24sIGFuZCByZXN1bHQgb2YgREVHIGFuYWx5c2lzOgoKYGBge3J9CiMgY3JlYXRlIERFU2VxRGF0YVNldCBpbnN0YW5jZQpkZHMgPSAgREVTZXFEYXRhU2V0RnJvbU1hdHJpeCgKICBjb3VudERhdGEgPSBybmFfYXNzYXksICMgaW5wdXQgd2l0aCBjb3VudHMgZm9yIGdlbmVzCiAgY29sRGF0YSA9IG1ldGFkYXRhRVJCQjIsICMgY29sRGF0YSByb3dzIG11c3QgbWF0Y2ggY291bnREYXRhIGNvbHVtbnMKICBkZXNpZ24gPSB+IEFtcGxpZmllZCkgIyBmb3JtdWxhIGhvdyB0aGUgY291bnRzIGZvciBlYWNoIGdlbmUgZGVwZW5kIG9uIGNvbERhdGEKYGBgCgpUaGUgY291bnRzIHRoYXQgSSBwcm92aWRlZCBpbiB0aGUgcm5hX2Fzc2F5IGFyZSBub3Qgbm9ybWFsaXplZCwgYW5kIHRoaXMgaXMgZXhwZWN0ZWQgYnkgdGhlIGBERVNlcSgpYCBmdW5jdGlvbiwgYmFzZWQgb24gdGhlIGRvY3VtZW50YXRpb24gYXQgYmlvY29uZHVjdGVyLm9yZy4KCiMjIyBSdW4gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMKClRoZSBgREVTRXEoKWAgZnVuY3Rpb24gcGVyZm9ybXMgZXN0aW1hdGlvbiBvZiBzaXplIGZhY3RvcnMsIGVzdGltYXRpb24gb2YgZGlzcGVyc2lvbiwgTmVnYXRpdmUgQmlub21pYWwgR0xNIGZpdHRpbmcgYW5kIFdhbGQgc3RhdGlzdGljcy4KCmBgYHtyfQojIFJ1biBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcwpkZHMgPC0gREVTZXEoZGRzKQpgYGAKCk5hbWVzIG9mIHRoZSBlc3RpbWF0ZWQgZWZmZWN0cyAoY29lZmZpY2llbnRzKSBvZiB0aGUgbW9kZWw6CgpgYGB7cn0KcmVzdWx0c05hbWVzKGRkcykKYGBgCgpUbyBhY2Nlc3MgcmVzdWx0cyBvZiBERUcgYW5hbHlzaXMsIGNhbGxpbmcgdGhlIGByZXN1bHRzKClgIGZ1bmN0aW9uOgoKYGBge3J9CnJlcyA9IHJlc3VsdHMoZGRzKQpgYGAKClRvcCAxMCBtb3N0IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBvcmRlcmVkIGJ5IHAtYWRqdXN0ZWQgdmFsdWU6CgpgYGB7cn0KIyBvcmRlciBieSBwLWFkanVzdGVkIHZhbHVlCnRvcF8xMF9nZW5lc19wYWRqID0gcmVzW29yZGVyKHJlcyRwYWRqKVsxOjEwXSxdCiMgcHJpbnQKcHJpbnQodG9wXzEwX2dlbmVzX3BhZGopCmBgYAoKVG9wIDEwIHVwcmVndWxhdGVkIGdlbmVzIGJhc2VkIG9uIHRoZSBmb2xkIGNoYW5nZTogCgpgYGB7cn0KIyBvcmRlciBieSBsb2cyIGZvbGQgY2hhbmdlCiMgd2hlbiB1c2luZyBkZXNjZW5kaW5nIG9yZGVyLCBsb2cyID4gMAojIGFuZCBzbyByZXR1cm5zIHRvcCAxMCB1cHJlZ3VsYXRlZCBnZW5lcwp0b3BfMTBfZ2VuZXNfbG9nMmZjX3VwID0gcmVzW29yZGVyKHJlcyRsb2cyRm9sZENoYW5nZSwgZGVjcmVhc2luZyA9IFRSVUUpWzE6MTBdLF0KcHJpbnQodG9wXzEwX2dlbmVzX2xvZzJmY191cCkKYGBgCgpUb3AgMTAgZG93bnJlZ3VsYXRlZCBnZW5lcyBiYXNlZCBvbiB0aGUgZm9sZCBjaGFuZ2U6IAoKYGBge3J9CiMgb3JkZXIgYnkgbG9nMiBmb2xkIGNoYW5nZQojIHdoZW4gdXNpbmcgYXNjZW5kaW5nIG9yZGVyLCBsb2cyIDwgMAojIGFuZCBzbyByZXR1cm5zIHRvcCAxMCBkb3ducmVndWxhdGVkIGdlbmVzCnRvcF8xMF9nZW5lc19sb2cyZmNfZG93biA9IHJlc1tvcmRlcihyZXMkbG9nMkZvbGRDaGFuZ2UsIGRlY3JlYXNpbmcgPSBGQUxTRSlbMToxMF0sXQpwcmludCh0b3BfMTBfZ2VuZXNfbG9nMmZjX2Rvd24pCmBgYAoKIyMgUGF0aHdheSBFbnJpY2htZW50CgpSZXF1aXJlZCBwYWNrYWdlczoKCmBgYHtyfQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoImNsdXN0ZXJQcm9maWxlciIsIHF1aWV0bHkgPSBUUlVFKSkKICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiY2x1c3RlclByb2ZpbGVyIikKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJvcmcuSHMuZWcuZGIiLCBxdWlldGx5ID0gVFJVRSkpCiAgQmlvY01hbmFnZXI6Omluc3RhbGwoIm9yZy5Icy5lZy5kYiIpCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiZW5yaWNocGxvdCIsIHF1aWV0bHkgPSBUUlVFKSkKICBpbnN0YWxsLnBhY2thZ2VzKCJlbnJpY2hwbG90IikKCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQpsaWJyYXJ5KGVucmljaHBsb3QpCmxpYnJhcnkob3JnLkhzLmVnLmRiKQpgYGAKClVzaW5nIGRpZmZlcmVudGlhbCBleHByZXNzZWQgZ2VuZXMsIHdoaWNoIHdlcmUgb2J0YWluZWQgYnkgREVTZXEoKSBmdW5jdGlvbiwgd2l0aCBwLWFkanVzdGVkIDwgMC4wNToKCmBgYHtyfQojIGZpbHRlciBERVNFcSByZXN1bHRzIHRvIGtlZXAgCiMgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIHdpdGggcC1hZGp1c3RlZCA8IDAuMDUKcmVzX3NpZ25pZmljYW50ID0gcmVzW3JlcyRwYWRqPDAuMDUsXQoKIyBzZXBhcmF0ZSBpbnRvIG92ZXItIGFuZCB1bmRlcmV4cHJlc3NlZCBieSBsb2cyIGZvbGQgY2hhbmdlCgojIG92ZXJleHByZXNzZWQKcmVzX292ZXIgID0gcm93bmFtZXMocmVzX3NpZ25pZmljYW50W3Jlc19zaWduaWZpY2FudCRsb2cyRm9sZENoYW5nZSA+IDAsXSkKCiMgdW5kZXJleHByZXNzZWQKcmVzX3VuZGVyID0gcm93bmFtZXMocmVzX3NpZ25pZmljYW50W3Jlc19zaWduaWZpY2FudCRsb2cyRm9sZENoYW5nZSA8IDAsXSkKYGBgCgpHZW5lIE9udG9sb2d5IChHTykgZW5yaWNobWVudCBhbmFseXNpczoKCmBgYHtyfQojIEdPIGVucmljaG1lbnQgYW5hbHlzaXMKZ29fcmVzdWx0c19vdmVyID0gZW5yaWNoR08oCiAgZ2VuZSAgICAgICAgICA9IHJlc19vdmVyLCAjIG92ZXJleHByZXNzZWQgZ2VuZXMgbGlzdAogIE9yZ0RiICAgICAgICAgPSBvcmcuSHMuZWcuZGIsICMgaHVtYW5zCiAga2V5VHlwZSAgICAgICA9ICJTWU1CT0wiLCAgCiAgb250ICAgICAgICAgICA9ICJCUCIsICMgYmlvbG9naWNhbCBwcm9jZXNzZXMKICBwQWRqdXN0TWV0aG9kID0gIkJIIiwgCiAgcHZhbHVlQ3V0b2ZmICA9IDAuMDUsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQpgYGAKCkVucmljaGVkIGJpb2xvZ2ljYWwgcHJvY2Vzc2VzIGFzc29jaWF0ZWQgd2l0aCB0aGUgb3ZlcmV4cHJlc3NlZCBnZW5lczoKCmBgYHtyfQojIHByaW50IHRvcCA2IHJlc3VsdHMKcHJpbnQoaGVhZChnb19yZXN1bHRzX292ZXIpKQpgYGAKClBsb3Qgb2YgZW5yaWNoZWQgYmlvbG9naWNhbCBwcm9jZXNzZXM6CgpgYGB7cn0KZG90cGxvdChnb19yZXN1bHRzX292ZXIsIHNob3dDYXRlZ29yeSA9IDEwKSArIAogIGdndGl0bGUoIkdlbmUgT250b2xvZ3kgRW5yaWNobWVudCAtIG92ZXJleHByZXNzZWQiKQpgYGAKCkdPIGFuYWx5c2lzIG9mIHRoZSB1bmRlcmV4cHJlc3NlZCBnZW5lczoKCmBgYHtyfQpnb19yZXN1bHRzX3VuZGVyID0gZW5yaWNoR08oCiAgZ2VuZSAgICAgICAgICA9IHJlc191bmRlciwgIyB1bmRlciBleHByZXNzZWQgZ2VuZXMgbGlzdAogIE9yZ0RiICAgICAgICAgPSBvcmcuSHMuZWcuZGIsICMgaHVtYW5zCiAga2V5VHlwZSAgICAgICA9ICJTWU1CT0wiLCAgCiAgb250ICAgICAgICAgICA9ICJCUCIsICMgYmlvbG9naWNhbCBwcm9jZXNzZXMKICBwQWRqdXN0TWV0aG9kID0gIkJIIiwgCiAgcHZhbHVlQ3V0b2ZmICA9IDAuMDUsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQpgYGAKCkVucmljaGVkIGJpb2xvZ2ljYWwgcHJvY2Vzc2VzIGFzc29jaWF0ZWQgd2l0aCB0aGUgdW5kZXJleHByZXNzZWQgZ2VuZXM6CgpgYGB7cn0KIyBwcmludCB0b3AgNiByZXN1bHRzCnByaW50KGhlYWQoZ29fcmVzdWx0c191bmRlcikpCmBgYAoKUGxvdCBvZiB0aGUgZW5yaWNoZWQgcGF0aHdheXMgcmVsYXRlZCB0byB0aGUgdW5kZXJleHByZXNzZWQgZ2VuZXM6CgpgYGB7cn0KZG90cGxvdChnb19yZXN1bHRzX3VuZGVyLCBzaG93Q2F0ZWdvcnkgPSAxMCkgKwogIGdndGl0bGUoIkdlbmUgT250b2xvZ3kgRW5yaWNobWVudCAtIFVuZGVyZXhwcmVzc2VkIikKYGBgCgpJbnN0YWxsaW5nIHBhY2thZ2VzIGZvciBwYXRod2F5IGVucmljaG1lbnQgYW5hbHlzaXMgdXNpbmcgUmVhY3RvbWU6CgpgYGB7cn0KaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJwYXRodmlldyIsIHF1aWV0bHkgPSBUUlVFKSkKICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgicGF0aHZpZXciKQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIlJlYWN0b21lUEEiLCBxdWlldGx5ID0gVFJVRSkpCiAgQmlvY01hbmFnZXI6Omluc3RhbGwoIlJlYWN0b21lUEEiKQoKbGlicmFyeShSZWFjdG9tZVBBKQpsaWJyYXJ5KHBhdGh2aWV3KQpgYGAKCktFR0cgKEt5b3RvIEVuY3ljbG9wZWRpYSBvZiBHZW5lcyBhbmQgR2Vub21lcykgZW5yaWNobWVudCBhbmFseXNpczoKCmBgYHtyfQojIG1hcCBnZW5lcyBjb2RlcyB0byBlbnRyZXogLSByZXF1aXJlZCB0byB1c2UgUmVhY3RvbWUgYW5kIEtlZ2cgZnVuY3Rpb25zCmdlbmVfZW50cmV6X292ZXIgPSBiaXRyKAogIHJlc19vdmVyLAogIGZyb21UeXBlID0gIlNZTUJPTCIsCiAgdG9UeXBlICAgPSAiRU5UUkVaSUQiLAogIE9yZ0RiICAgID0gb3JnLkhzLmVnLmRiCikKCmdlbmVfZW50cmV6X3VuZGVyID0gYml0cigKICByZXNfdW5kZXIsCiAgZnJvbVR5cGUgPSAiU1lNQk9MIiwKICB0b1R5cGUgICA9ICJFTlRSRVpJRCIsCiAgT3JnRGIgICAgPSBvcmcuSHMuZWcuZGIKKQoKa2VnZ19yZXN1bHRzX292ZXIgPSBlbnJpY2hLRUdHKAogIGdlbmUgICAgICAgICAgPSBnZW5lX2VudHJlel9vdmVyWywyXSwKICBvcmdhbmlzbSAgICAgID0gImh1bWFuIiwgICAKICBwQWRqdXN0TWV0aG9kID0gIkJIIiwKICBwdmFsdWVDdXRvZmYgID0gMC4wNSwKICBxdmFsdWVDdXRvZmYgID0gMC4wNQopCgprZWdnX3Jlc3VsdHNfdW5kZXIgPSBlbnJpY2hLRUdHKAogIGdlbmUgICAgICAgICAgPSBnZW5lX2VudHJlel91bmRlclssMl0sCiAgb3JnYW5pc20gICAgICA9ICJodW1hbiIsICAgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcHZhbHVlQ3V0b2ZmICA9IDAuMDUsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQpgYGAKClNpZ25pZmljYW50bHkgZW5yaWNoZWQgS0VHRyBwYXRod2F5cyBvciBmdW5jdGlvbmFsIGNhdGVnb3JpZXMgZm9yIG1vc3Qgb3ZlcmV4cHJlc3NlZCBnZW5lczoKCmBgYHtyfQpwcmludChoZWFkKGtlZ2dfcmVzdWx0c19vdmVyKSkKYGBgCgpgYGB7cn0KZG90cGxvdChrZWdnX3Jlc3VsdHNfb3Zlciwgc2hvd0NhdGVnb3J5ID0gMTApICsgZ2d0aXRsZSgiS2VnZyAtIG92ZXJleHByZXNzZWQiKQpgYGAKClNpZ25pZmljYW50bHkgZW5yaWNoZWQgS0VHRyBwYXRod2F5cyBvciBmdW5jdGlvbmFsIGNhdGVnb3JpZXMgZm9yIG1vc3QgdW5kZXJ4cHJlc3NlZCBnZW5lczoKCmBgYHtyfQpwcmludChoZWFkKGtlZ2dfcmVzdWx0c191bmRlcikpCmBgYAoKYGBge3J9CmRvdHBsb3Qoa2VnZ19yZXN1bHRzX3VuZGVyLCBzaG93Q2F0ZWdvcnkgPSAxMCkgKyBnZ3RpdGxlKCJLZWdnIC0gdW5kZXJleHByZXNzZWQiKQpgYGAKClJlYWN0b21lIHJlc3VsdHMuCgpgYGB7cn0KcmVhY3RvbWVfcmVzdWx0c19vdmVyID0gZW5yaWNoUGF0aHdheSgKICBnZW5lICAgICAgICAgID0gZ2VuZV9lbnRyZXpfb3ZlclssMl0sCiAgb3JnYW5pc20gICAgICA9ICJodW1hbiIsICAgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcHZhbHVlQ3V0b2ZmICA9IDAuMDUsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUsCikKCnJlYWN0b21lX3Jlc3VsdHNfdW5kZXIgPSBlbnJpY2hQYXRod2F5KAogIGdlbmUgICAgICAgICAgPSBnZW5lX2VudHJlel91bmRlclssMl0sCiAgb3JnYW5pc20gICAgICA9ICJodW1hbiIsICAgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcHZhbHVlQ3V0b2ZmICA9IDAuMDUsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUsCikKYGBgCgpQYXRod2F5cyBhc3NvY2lhdGVkIHdpdGggb3ZlcmV4cHJlc3NlZCBnZW5lczoKCmBgYHtyfQpwcmludChoZWFkKHJlYWN0b21lX3Jlc3VsdHNfb3ZlcikpCmBgYAoKYGBge3J9CmRvdHBsb3QocmVhY3RvbWVfcmVzdWx0c19vdmVyLCBzaG93Q2F0ZWdvcnkgPSAxMCkgKyBnZ3RpdGxlKCJSZWFjdG9tZSAtIG92ZXJ4cHJlc3NlZCIpCmBgYAoKUGF0aHdheXMgYXNzb2NpYXRlZCB3aXRoIHVuZGVyZXhwcmVzc2VkIGdlbmVzOgoKYGBge3J9CnByaW50KGhlYWQocmVhY3RvbWVfcmVzdWx0c191bmRlcikpCmBgYAoKYGBge3J9CmRvdHBsb3QocmVhY3RvbWVfcmVzdWx0c191bmRlciwgc2hvd0NhdGVnb3J5PTEwKSArIGdndGl0bGUoIlJlYWN0b21lIC0gdW5kZXJleHByZXNzZWQiKQpgYGAKCgojIyBWYXJpYW5jZSBzdGFiaWxpc2VkIHRyYW5zZm9ybWVkIGV4cHJlc3Npb24gdmFsdWVzCgpBcHBseWluZyBhIHZhcmlhbmNlIHN0YWJpbGl6aW5nIHRyYW5zZm9ybWF0aW9uIChWU1QpIHRvIHRoZSBSTkEtc2VxIGNvdW50IGRhdGEuClZTVCBhdXRvbWF0aWNhbGx5IG5vcm1hbGl6ZXMgdGhlIGNvdW50IGRhdGEsIHByb3ZpZGluZyBtYXRyaXggb2YgdmFsdWVzIHdoaWNoIGFyZSBhcHByb3hpbWF0ZWx5IGhvbW9za2VkYXN0aWMgKGhhdmUgY29uc3RhbnQgdmFyaWFuY2UgYWxvbmcgdGhlIHJhbmdlIG9mIG1lYW4gdmFsdWVzKS4KCmBgYHtyfQojIHZhcmlhbmNlIHN0YWJpbGl6aW5nIHRyYW5zZm9ybWF0aW9uCnZzdCA9IHZzdChkZHMpCmBgYAoKIyMgUENBIHBsb3QgYW5kIGEgaGVhdG1hcAoKUENBIHBsb3Q6CgpgYGB7cn0KIyBQQ0EgcGxvdCBvZiB0aGUgdnN0IHJlc3VsdHMgZ3JvdXBlZCBieSB0aGUgQW1wbGlmaWVkIHN0YXR1cwpwbG90UENBKHZzdCwgaW50Z3JvdXA9YygiQW1wbGlmaWVkIikpCmBgYAoKUGFjYWtnZXMgZm9yIEhlYXRtYXA6CgpgYGB7cn0KIyBpbnN0YWxsIHBhY2thZ2VzIGZvciBoZWF0bWFwIAppZiAoIXJlcXVpcmVOYW1lc3BhY2UoInBoZWF0bWFwIiwgcXVpZXRseSA9IFRSVUUpKQogIGluc3RhbGwucGFja2FnZXMoInBoZWF0bWFwIikKCmxpYnJhcnkocGhlYXRtYXApCmBgYAoKU3Vic2V0IG9mIHRoZSBtb3N0IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyB0byB2aXN1YWxpemU6CgpgYGB7cn0KIyBzb3J0IGJ5IHAtYWRqdXN0ZWQgCmdlbmVzX3NvcnRlZCA9IG9yZGVyKHJlcyRwYWRqKQoKIyBWU1QgcmVzdWx0cyBmb3IgdG9wIDIwIGdlbmVzCnZzdF90b3AyMCA9IGFzc2F5KHZzdClbZ2VuZXNfc29ydGVkWzE6MjBdLF0KYGBgCgpQbG90dGluZyB0aGUgaGVhdG1hcDoKCmBgYHtyfQojIGNvbHVtbiBmb3IgYW5ub3RhdGlvbgphbm5vdGF0aW9uX2NvbHVtbiA9IGFzLmRhdGEuZnJhbWUoY29sRGF0YShkZHMpWywgIkFtcGxpZmllZCIsIGRyb3AgPSBGQUxTRV0pCgpwaGVhdG1hcCgKICB2c3RfdG9wMjAsCiAgY2x1c3Rlcl9yb3dzID0gVFJVRSwgICAgICAKICBjbHVzdGVyX2NvbHMgPSBUUlVFLCAgCiAgc2NhbGUgPSAncm93JywKICBzaG93X2NvbG5hbWVzID0gRkFMU0UsCiAgc2hvd19yb3duYW1lcyA9IFRSVUUsCiAgYW5ub3RhdGlvbl9jb2wgPSBhbm5vdGF0aW9uX2NvbHVtbiwKICBtYWluID0gIkhlYXRtYXAgb2YgR2VuZSBFeHByZXNzaW9uIGJ5IEVSQkIyIEFtcGxpZmllZCBzdGF0dXMiKQoKYGBgCgojIyBPdmVyYWxsIHN1cnZpdmFsIG1vZGVsIHVzaW5nIHRoZSBnbG1uZXQgcGFja2FnZQoKUGFja2FnZXM6CgpgYGB7cn0KaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJnbG1uZXQiLCBxdWlldGx5ID0gVFJVRSkpCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2xtbmV0IikKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJzdXJ2aXZhbCIsIHF1aWV0bHkgPSBUUlVFKSkKICBpbnN0YWxsLnBhY2thZ2VzKCJzdXJ2aXZhbCIpCmlmICghcmVxdWlyZU5hbWVzcGFjZSgic3Vydm1pbmVyIiwgcXVpZXRseSA9IFRSVUUpKQogIGluc3RhbGwucGFja2FnZXMoInN1cnZtaW5lciIpCmxpYnJhcnkoZ2xtbmV0KQpsaWJyYXJ5KHN1cnZpdmFsKQpsaWJyYXJ5KHN1cnZtaW5lcikKYGBgCgpEYXRhIHByZXBhcmF0aW9uOiBleHRyYWN0aW5nIHN1cnZpdmFsIHRpbWVzIChub24temVybyBhbmQgbm9uIE5BKSwgZXZlbnQgc3RhdHVzIGFuZCB0aGUgY29ycmVzcG9uZGluZyBzdWJzZXQgb2YgdGhlIFZTVCBtYXRyaXguIFZTVCBtYXRyaXggaXMgc3Vic2V0IGJhc2VkIG9uIGNvcnJlc3BvbmRlbmNlIG9mIFNhbXBsZSBJRCBhbmQgUGF0aWVudCBJRCBmcm9tIGEgY2xpbmljYWwgaW5mbyBkYXRhOgoKYGBge3J9CiMgdnN0LXRyYW5zZm9ybWVkIG1hdHJpeAp2c3RfbWF0cml4ID0gYXNzYXkodnN0KQpgYGAKCmBgYHtyfQojIHRyYW5zZm9ybSBwYXRpZW50IGlkZW50aWZpZXIgdG8gbWF0Y2ggc2FtcGxlIElEcyBpbiB2c3RfbWF0cml4CiMgYXMgYSByZXN1bHQsIHRyYW5zZm9ybXMgVENHQS0zQy1BQUFVIHRvIFRDR0EuM0MuQUFBVQpzYW1wbGVfaWRzID0gZ3N1YigiLSIsICIuIiwgZGF0YV9wYXRpZW50JFguUGF0aWVudC5JZGVudGlmaWVyWzU6bnJvdyhkYXRhX3BhdGllbnQpXSkKIyBleHRyYWN0IHNhbXBsZSBpZHMgZnJvbSB2c3Qgd2l0aG91dCBzdWZmaXggLjAxCnNhbXBsZV9pZHNfdnN0ID0gc3Vic3RyKGNvbG5hbWVzKHZzdF9tYXRyaXgpLCAxLCAxMikKCiMgY29udmVydCBzdXJ2aXZhbF90aW1lIGFuZCBldmVudF9zdGF0dXMgdG8gbnVtZXJpYyAKc3Vydml2YWxfdGltZSA9IGFzLm51bWVyaWMoZGF0YV9wYXRpZW50JE92ZXJhbGwuU3Vydml2YWwuLk1vbnRocy5bNTpucm93KGRhdGFfcGF0aWVudCldKQpldmVudF9zdGF0dXMgPSBkYXRhX3BhdGllbnQkT3ZlcmFsbC5TdXJ2aXZhbC5TdGF0dXNbNTpucm93KGRhdGFfcGF0aWVudCldIApldmVudF9zdGF0dXMgPSBpZmVsc2UoZXZlbnRfc3RhdHVzID09ICIxOkRFQ0VBU0VEIiwgMSwgMCkKCiMgZmlsdGVyIG91dCBzdXJ2aXZhbCB0aW1lIHRoYXQgYXJlIGxlc3MgdGhhbiBlcXVhbCAwCnZhbGlkX2luZGV4ID0gd2hpY2goc3Vydml2YWxfdGltZSA+IDApIApzdXJ2aXZhbF90aW1lID0gc3Vydml2YWxfdGltZVt2YWxpZF9pbmRleF0gCmV2ZW50X3N0YXR1cyA9IGV2ZW50X3N0YXR1c1t2YWxpZF9pbmRleF0gCnNhbXBsZV9pZHMgPSBzYW1wbGVfaWRzW3ZhbGlkX2luZGV4XQoKIyByZW1vdmUgcm93cyB3aXRoIE5BIHZhbHVlcwpjb21wbGV0ZV9jYXNlc19pbmRleCA9IGNvbXBsZXRlLmNhc2VzKHN1cnZpdmFsX3RpbWUsIGV2ZW50X3N0YXR1cykgCnN1cnZpdmFsX3RpbWUgPSBzdXJ2aXZhbF90aW1lW2NvbXBsZXRlX2Nhc2VzX2luZGV4XSAKZXZlbnRfc3RhdHVzID0gZXZlbnRfc3RhdHVzW2NvbXBsZXRlX2Nhc2VzX2luZGV4XSAKc2FtcGxlX2lkcyA9IHNhbXBsZV9pZHNbY29tcGxldGVfY2FzZXNfaW5kZXhdCmBgYAoKYGBge3J9CiMgbWF0Y2ggc2FtcGxlIElEcyBkZXJpdmVkIGZyb20gUGF0aWVudCBJRHMgYW5kIFZTVCBzYW1wbGUgSURzCiMga2VlcCB0aG9zZSB0aGF0IHByZXNlbnQgaW4gYm90aAptYXRjaGluZ19pZHMgPSBpbnRlcnNlY3Qoc2FtcGxlX2lkcywgc2FtcGxlX2lkc192c3QpCiMgdGhlaXIgaW5kZXhlcwptYXRjaGluZ19pbmRleCA9IHdoaWNoKHNhbXBsZV9pZHMgJWluJSBtYXRjaGluZ19pZHMpCmBgYAoKYGBge3J9CiMgc3Vic2V0IHN1cnZpdmFsX3RpbWUgYW5kIGV2ZW50X3N0YXR1cyBieSBpbmRleGVzIG9mIG1hdGNoaW5nIGlkcwpzdXJ2aXZhbF90aW1lID0gc3Vydml2YWxfdGltZVttYXRjaGluZ19pbmRleF0KZXZlbnRfc3RhdHVzID0gZXZlbnRfc3RhdHVzW21hdGNoaW5nX2luZGV4XQojIHN1YnNldCB2c3RfbWF0cml4IGJ5IG1hdGNoaW5nIGlkcyAKbWF0Y2hpbmdfaWRzX3ZzdCA9IGNvbG5hbWVzKHZzdF9tYXRyaXgpW3N1YnN0cihjb2xuYW1lcyh2c3RfbWF0cml4KSwgMSwgMTIpICVpbiUgbWF0Y2hpbmdfaWRzXQoKdnN0X21hdHJpeCA9IHZzdF9tYXRyaXhbLCBtYXRjaGluZ19pZHNfdnN0XQpgYGAKClRyYW5zcG9zZSB2c3RfbWF0cml4IHNvIHRoYXQgc2FtcGxlcyBhcmUgcm93cywgZ2VuZXMgYXJlIGNvbHVtbnM6CgpgYGB7cn0gCnZzdF9tYXRyaXggPSB0KHZzdF9tYXRyaXgpCmBgYAoKQ2hlY2sgbm8gTkE6CgpgYGB7cn0Kc3VtKGlzLm5hKHN1cnZpdmFsX3RpbWUpKSAgCnN1bShpcy5uYShldmVudF9zdGF0dXMpKSAKc3VtKGlzLm5hKHZzdF9tYXRyaXgpKSAKYGBgCgpDcmVhdGUgc3Vydml2YWwgb2JqZWN0OgoKYGBge3J9CnN1cnZpdmFsX29iamVjdCA9IFN1cnYodGltZSA9IHN1cnZpdmFsX3RpbWUsIGV2ZW50ID0gZXZlbnRfc3RhdHVzKSAKYGBgCgpDb3ggbW9kZWwgd2l0aCBhbHBoYSA9IDEgdG8gYXBwbHkgbGFzc28gcGVuYWx0eToKCmBgYHtyfQojIENveCBtb2RlbCBhbmQgTGFzc28gcmVndWxhcml6YXRpb24gdXNpbmcgZ2xtbmV0IApjb3hfbW9kZWwgPSBnbG1uZXQodnN0X21hdHJpeCwgCiAgICAgICAgICAgICAgICAgICBzdXJ2aXZhbF9vYmplY3QsIAogICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gImNveCIsCiAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDEpICMgbGFzc28gcGVuYWx0eQpgYGAKCkstZm9sZCAoNSkgY3Jvc3MtdmFsaWRhdGlvbiBmb3IgZ2xtbmV0OgoKYGBge3J9CiMgcHJvZHVjZXMgYSBwbG90IGFuZCByZXR1cm5zIGEgdmFsdWUgZm9yIGxhbWJkYQpjdl9maXQgPSBjdi5nbG1uZXQodnN0X21hdHJpeCwKICAgICAgICAgICAgICAgICAgIHN1cnZpdmFsX29iamVjdCwKICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJjb3giLAogICAgICAgICAgICAgICAgICAgbmZvbGRzID0gNSkgIyByZWR1Y2VkIHRvIDUgZHVlIHRvIHNsb3cgZXhlY3V0aW9uCgojIGJlc3QgbGFtYmRhCmJlc3RfbGFtYmRhID0gY3ZfZml0JGxhbWJkYS5taW4KcHJpbnQoYmVzdF9sYW1iZGEpCmBgYAoKU3Vydml2YWwgcmlzazoKCmBgYHtyfQojIHN1cnZpdmFsIHJpc2sKcmlza19zY29yZSA9IHByZWRpY3QoY294X21vZGVsLAogICAgICAgICAgICAgICAgICAgICBzID0gYmVzdF9sYW1iZGEsCiAgICAgICAgICAgICAgICAgICAgIG5ld3ggPSB2c3RfbWF0cml4KQoKcHJpbnQoaGVhZChyaXNrX3Njb3JlKSkKYGBgCgpQbG90IGRhdGE6CgpgYGB7cn0KIyByaXNrIHNjb3JlcyBhcyBkYXRhIGZyYW1lIHRvIHVzZSBpbiBhIHBsb3QKcmlza19kYXRhID0gZGF0YS5mcmFtZShzdXJ2aXZhbF90aW1lLAogICAgICAgICAgICAgICAgICAgICAgIGV2ZW50X3N0YXR1cywKICAgICAgICAgICAgICAgICAgICAgICByaXNrX3Njb3JlID0gcmlza19zY29yZVssMV0pCgojIGFzc2lnbiByaXNrIGNhdGFnZXJ5IGJhc2VkIG9uIHJpc2sgc2NvcmUKcmlza19kYXRhJHJpc2tfZ3JvdXAgPSBpZmVsc2Uocmlza19kYXRhJHJpc2tfc2NvcmUgPiBtZWRpYW4ocmlza19kYXRhJHJpc2tfc2NvcmUpLCAiSGlnaCBSaXNrIiwgIkxvdyBSaXNrIikKCiMgZml0IHN1cnZpdmFsIGN1cnZlcwpzdXJ2X2N1cnZlc19maXQgPSBzdXJ2Zml0KHN1cnZpdmFsX29iamVjdCB+IHJpc2tfZ3JvdXAsIGRhdGEgPSByaXNrX2RhdGEpIAoKIyBLYXBsYW4tTWVpZXIgY3VydmVzIApnZ3N1cnZwbG90KHN1cnZfY3VydmVzX2ZpdCwKICAgICAgICAgICBkYXRhID0gcmlza19kYXRhLCAKICAgICAgICAgICBwdmFsID0gVFJVRSwgCiAgICAgICAgICAgcmlzay50YWJsZSA9IFRSVUUsIAogICAgICAgICAgIGNvbmYuaW50ID0gVFJVRSwgCiAgICAgICAgICAgcGFsZXR0ZSA9IGMoIiNCMjIyMjIiLCAiIzIyOEIyMiIpLCAKICAgICAgICAgICB0aXRsZSA9ICJLYXBsYW4tTWVpZXIgU3Vydml2YWwgQ3VydmVzIiwgCiAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gIlJpc2sgR3JvdXAiLCAKICAgICAgICAgICBsZWdlbmQubGFicyA9IGMoIkxvdyBSaXNrIiwgIkhpZ2ggUmlzayIpKQoKYGBgCgoKCg==